﻿using Awsc.DataAcquisitionSys.Core.Model.Config;
using Awsc.DataAcquisitionSys.Core.Models.POCO;
using Awsc.DataAcquisitionSys.Core.Repository;
using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using System.Collections.Concurrent;
using System.Data;
using System.Diagnostics;

namespace Awsc.DataAcquisitionSys.Core.Databases
{
    public class SentinelDataWriter
    {
        private const int BatchSize = 500;       // 每批处理的数据点数量
        private const int CommitIntervalMs = 50; // 最大提交间隔(ms)

        private bool _isRecording = true;
        private bool _disposed;
        private List<SensorConfig> _currentSensorList;
        private SqliteConnection _connection;
        private SqliteCommand _insertCommand;
        private BlockingCollection<SensorDataRow> _dataQueue = new();
        private Thread _writerThread;
        private readonly object _schemaLock = new();
        private DeviceConfig _deviceConfig;
        private string _tableName;

        public SentinelDataWriter(IOptionsMonitor<DeviceConfig> optionsMonitor)
        {
            this._deviceConfig = optionsMonitor.CurrentValue;
        }


        public void StartRecording(string tableName)
        {
            this._tableName = tableName;
            this._currentSensorList = _deviceConfig.GetAllSensorConfig();
            PrepareInsertCommand();

            // 启动高性能写入线程
            _writerThread = new Thread(async () => await WriteProcessingLoop())
            {
                Priority = ThreadPriority.Highest,
                IsBackground = true
            };
            _writerThread.Start();
        }
        public void StopRecording()
        {
            _isRecording = false;
            Dispose();
        }

        public void Dispose()
        {
            if (_disposed) return;

            _disposed = true;
            _dataQueue.CompleteAdding();

            // 等待写入线程结束（最多2秒）
            if (_writerThread != null && _writerThread.IsAlive)
            {
                _writerThread.Join(2000);
            }
            // 优化关闭前的数据库整理
            if (_connection != null && _connection.State == ConnectionState.Open)
            {
                using var cmd = new SqliteCommand("PRAGMA optimize", _connection);
                cmd.ExecuteNonQuery();
                _connection.Close();
            }
            _insertCommand?.Dispose();
            _connection?.Dispose();
            _currentSensorList = null;
            GC.SuppressFinalize(this);
        }

        private void PrepareInsertCommand()
        {
            lock (_schemaLock)
            {
                // 释放之前的命令
                _insertCommand?.Dispose();

                var columns = string.Join(", ", _currentSensorList.Select(s => $"`{s.Name}`"));
                var parameters = string.Join(", ", _currentSensorList.Select(s => $"@{s.Name}"));



                _insertCommand = new SqliteCommand(
                    $"INSERT INTO `{this._tableName}` (时间, {columns}) " +
                    $"VALUES (@MissionId, @Timestamp, {parameters})",
                    _connection);

                // 添加参数
                _insertCommand.Parameters.Add("@MissionId", SqliteType.Integer);
                _insertCommand.Parameters.Add("@Timestamp", SqliteType.Real);

                foreach (var sensor in _currentSensorList)
                {
                    if (sensor.IsCoil)
                    {
                        _insertCommand.Parameters.Add($"@{sensor.Name}", SqliteType.Text);
                    }
                    else
                    {
                        _insertCommand.Parameters.Add($"@{sensor.Name}", SqliteType.Real);
                    }

                }
            }
        }
        private async Task WriteProcessingLoop()
        {
            var batch = new List<SensorDataRow>(BatchSize);
            var lastCommitTime = DateTime.UtcNow;


            while (_isRecording && !_disposed && !_dataQueue.IsCompleted)
            {
                try
                {
                    // 从队列取数据
                    while (_dataQueue.TryTake(out var dataPoint, CommitIntervalMs))
                    {
                        batch.Add(dataPoint);
                        if (batch.Count >= BatchSize) break;
                    }

                    // 检查是否需要提交（达到批量大小或超时）
                    bool shouldCommit = batch.Count > 0 &&
                                       (batch.Count >= BatchSize ||
                                       (DateTime.UtcNow - lastCommitTime).TotalMilliseconds >= CommitIntervalMs);

                    if (!shouldCommit)
                    {
                        Thread.Sleep(1);
                        continue;
                    }

                    var sw = Stopwatch.StartNew();
                    int pointsProcessed = 0;

                    using (var transaction = _connection.BeginTransaction())
                    {
                        _insertCommand.Transaction = transaction;

                        foreach (var data in batch)
                        {
                            _insertCommand.Parameters["@Timestamp"].Value = data.Timestamp;

                            // 设置所有传感器值
                            foreach (var sensor in _currentSensorList)
                            {
                                if (data.Values.TryGetValue(sensor.Name, out object value) && value != null)
                                {

                                    _insertCommand.Parameters[$"@{sensor.Name}"].Value = value;
                                }
                                else
                                {
                                    _insertCommand.Parameters[$"@{sensor.Name}"].Value = DBNull.Value;
                                }
                            }

                            await _insertCommand.ExecuteNonQueryAsync();
                            pointsProcessed++;
                        }

                        await transaction.CommitAsync();
                    }

                    sw.Stop();
                    Console.WriteLine($"写入 {pointsProcessed} 个数据点，耗时 {sw.ElapsedMilliseconds}ms");

                    batch.Clear();
                    lastCommitTime = DateTime.UtcNow;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"写入错误: {ex.Message}");
                    Thread.Sleep(100);
                }
            }
        }
    }
}
